/*
 * @Author: fuhongliang-TSJ hongliang.fu@4d-bios.com
 * @Date: 2025-09-19 11:05:25
 * @LastEditTime: 2025-09-30 13:18:31
 * @LastEditors: fuhongliang-TSJ hongliang.fu@4d-bios.com
 * @Description: 
 * @FilePath: \lc_-esp32_-s3\main\blufi\blufi.c
 * 立创实战派ESP32-S3开发板
 * Copyright (c) 2025 by 4D Bios, All Rights Reserved. 
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_mac.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#if CONFIG_BT_CONTROLLER_ENABLED || !CONFIG_BT_NIMBLE_ENABLED
#include "esp_bt.h"
#endif

#include "esp_blufi_api.h"
#include "blufi.h"

#include "esp_blufi.h"
#include "common.h"

static const char *TAG = "BLUFI";

#define WIFI_CONNECTION_MAXIMUM_RETRY 2
#define INVALID_REASON                255
#define INVALID_RSSI                  -128

#define WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_PSK

static void blufi_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *param);

#define WIFI_LIST_NUM   10
#define BLUFI_NET_CONFIG_TIMEOUT    90   

static wifi_config_t sta_config;
static wifi_config_t ap_config;

static uint8_t wifi_retry = 0;

/* store the station info for send back to phone */
static bool gl_sta_connected = false;
static bool gl_sta_got_ip = false;
static bool ble_is_connected = false;
static uint8_t gl_sta_bssid[6];
static uint8_t gl_sta_ssid[32];
static int gl_sta_ssid_len;
static wifi_sta_list_t gl_sta_list;
static bool gl_sta_is_connecting = false;
static esp_blufi_extra_info_t gl_sta_conn_info;

static EventGroupHandle_t wifi_event_group;
EventBits_t  wifi_event_bit;

EventGroupHandle_t blufi_event_group = NULL; 
EventBits_t  blufi_event_bit;  

#define LEN_OF_WIFI_ENTITY_SSID         32
#define LEN_OF_WIFI_ENTITY_PWD          64

char app_ssid[LEN_OF_WIFI_ENTITY_SSID];
char app_pwd[LEN_OF_WIFI_ENTITY_PWD];

static void record_wifi_conn_info(int rssi, uint8_t reason)
{
    memset(&gl_sta_conn_info, 0, sizeof(esp_blufi_extra_info_t));
    if (gl_sta_is_connecting) {
        gl_sta_conn_info.sta_max_conn_retry_set = true;
        gl_sta_conn_info.sta_max_conn_retry = WIFI_CONNECTION_MAXIMUM_RETRY;
    } else {
        gl_sta_conn_info.sta_conn_rssi_set = true;
        gl_sta_conn_info.sta_conn_rssi = rssi;
        gl_sta_conn_info.sta_conn_end_reason_set = true;
        gl_sta_conn_info.sta_conn_end_reason = reason;
    }
}

static void wifi_connect(void)
{
    wifi_retry = 0;
    gl_sta_is_connecting = (esp_wifi_connect() == ESP_OK);
    record_wifi_conn_info(INVALID_RSSI, INVALID_REASON);
}

static bool wifi_reconnect(void)
{
    bool ret;
    if (gl_sta_is_connecting && wifi_retry++ < WIFI_CONNECTION_MAXIMUM_RETRY) {
        BLUFI_INFO("BLUFI WiFi starts reconnection\n");
        gl_sta_is_connecting = (esp_wifi_connect() == ESP_OK);
        record_wifi_conn_info(INVALID_RSSI, INVALID_REASON);
        ret = true;
    } else {
        ret = false;
    }
    return ret;
}

static int softap_get_current_connection_number(void)
{
    esp_err_t ret;
    ret = esp_wifi_ap_get_sta_list(&gl_sta_list);
    if (ret == ESP_OK)
    {
        return gl_sta_list.num;
    }

    return 0;
}

static void ip_event_handler(void* arg, esp_event_base_t event_base,
                                int32_t event_id, void* event_data)
{
    wifi_mode_t mode;

    switch (event_id) {
    case IP_EVENT_STA_GOT_IP: {
        esp_blufi_extra_info_t info;

        xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_BIT);
        esp_wifi_get_mode(&mode);

        memset(&info, 0, sizeof(esp_blufi_extra_info_t));
        memcpy(info.sta_bssid, gl_sta_bssid, 6);
        info.sta_bssid_set = true;
        info.sta_ssid = gl_sta_ssid;
        info.sta_ssid_len = gl_sta_ssid_len;
        gl_sta_got_ip = true;
        if (ble_is_connected == true) {
            esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_SUCCESS, softap_get_current_connection_number(), &info);
        } else {
            BLUFI_INFO("BLUFI BLE is not connected yet\n");
        }
        break;
    }
    default:
        break;
    }
    return;
}

static void wifi_event_handler(void* arg, esp_event_base_t event_base,
                                int32_t event_id, void* event_data)
{
    wifi_event_sta_connected_t *event;
    wifi_event_sta_disconnected_t *disconnected_event;
    wifi_mode_t mode;

    switch (event_id) {
    case WIFI_EVENT_STA_START:
        ESP_LOGD(TAG, "WIFI EVENT STA START\n");
        wifi_connect();
        break;
    case WIFI_EVENT_STA_CONNECTED:
        ESP_LOGD(TAG, "WIFI EVENT STA CONNECTED\n");
        gl_sta_connected = true;
        gl_sta_is_connecting = false;
        event = (wifi_event_sta_connected_t*) event_data;
        memcpy(gl_sta_bssid, event->bssid, 6);
        memcpy(gl_sta_ssid, event->ssid, event->ssid_len);
        gl_sta_ssid_len = event->ssid_len;
        break;
    case WIFI_EVENT_STA_DISCONNECTED:
        ESP_LOGD(TAG, "WIFI EVENT STA DISCONNECTED\n");
        /* Only handle reconnection during connecting */
        if (gl_sta_connected == false && wifi_reconnect() == false) {
            gl_sta_is_connecting = false;
            disconnected_event = (wifi_event_sta_disconnected_t*) event_data;
            record_wifi_conn_info(disconnected_event->rssi, disconnected_event->reason);
        }
        /* This is a workaround as ESP32 WiFi libs don't currently
           auto-reassociate. */
        gl_sta_connected = false;
        gl_sta_got_ip = false;
        memset(gl_sta_ssid, 0, 32);
        memset(gl_sta_bssid, 0, 6);
        gl_sta_ssid_len = 0;
        xEventGroupSetBits(wifi_event_group, WIFI_FAIL_BIT);
        break;
    case WIFI_EVENT_AP_START:
        esp_wifi_get_mode(&mode);

        /* TODO: get config or information of softap, then set to report extra_info */
        if (ble_is_connected == true) {
            if (gl_sta_connected) {
                esp_blufi_extra_info_t info;
                memset(&info, 0, sizeof(esp_blufi_extra_info_t));
                memcpy(info.sta_bssid, gl_sta_bssid, 6);
                info.sta_bssid_set = true;
                info.sta_ssid = gl_sta_ssid;
                info.sta_ssid_len = gl_sta_ssid_len;
                esp_blufi_send_wifi_conn_report(mode, gl_sta_got_ip ? ESP_BLUFI_STA_CONN_SUCCESS : ESP_BLUFI_STA_NO_IP, softap_get_current_connection_number(), &info);
            } else if (gl_sta_is_connecting) {
                esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONNECTING, softap_get_current_connection_number(), &gl_sta_conn_info);
            } else {
                esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_FAIL, softap_get_current_connection_number(), &gl_sta_conn_info);
            }
        } else {
            BLUFI_INFO("BLUFI BLE is not connected yet\n");
        }
        break;
    case WIFI_EVENT_SCAN_DONE: {
        uint16_t apCount = 0;
        esp_wifi_scan_get_ap_num(&apCount);
        if (apCount == 0) {
            BLUFI_INFO("Nothing AP found");
            break;
        }
        wifi_ap_record_t *ap_list = (wifi_ap_record_t *)malloc(sizeof(wifi_ap_record_t) * apCount);
        if (!ap_list) {
            BLUFI_ERROR("malloc error, ap_list is NULL");
            esp_wifi_clear_ap_list();
            break;
        }
        ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&apCount, ap_list));
        esp_blufi_ap_record_t * blufi_ap_list = (esp_blufi_ap_record_t *)malloc(apCount * sizeof(esp_blufi_ap_record_t));
        if (!blufi_ap_list) {
            if (ap_list) {
                free(ap_list);
            }
            BLUFI_ERROR("malloc error, blufi_ap_list is NULL");
            break;
        }
        for (int i = 0; i < apCount; ++i)
        {
            blufi_ap_list[i].rssi = ap_list[i].rssi;
            memcpy(blufi_ap_list[i].ssid, ap_list[i].ssid, sizeof(ap_list[i].ssid));
        }

        if (ble_is_connected == true) {
            esp_blufi_send_wifi_list(apCount, blufi_ap_list);
        } else {
            BLUFI_INFO("BLUFI BLE is not connected yet\n");
        }

        esp_wifi_scan_stop();
        free(ap_list);
        free(blufi_ap_list);
        break;
    }
    case WIFI_EVENT_AP_STACONNECTED: {
        wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
        BLUFI_INFO("station "MACSTR" join, AID=%d", MAC2STR(event->mac), event->aid);
        break;
    }
    case WIFI_EVENT_AP_STADISCONNECTED: {
        wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
        BLUFI_INFO("station "MACSTR" leave, AID=%d, reason=%d", MAC2STR(event->mac), event->aid, event->reason);
        break;
    }

    default:
        break;
    }
    return;
}

/**
 * @description: wifi初始化
 * @return {*}
 */
static void initialise_wifi(void)
{
    ESP_ERROR_CHECK(esp_netif_init());
    wifi_event_group = xEventGroupCreate();
    wifi_event_bit = WIFI_FAIL_BIT;
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
    assert(sta_netif);

    /* AP这里用不到
    esp_netif_t *ap_netif = esp_netif_create_default_wifi_ap();
    assert(ap_netif);
    */
   
    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL));
    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &ip_event_handler, NULL));

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
    ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
    record_wifi_conn_info(INVALID_RSSI, INVALID_REASON);
    ESP_ERROR_CHECK( esp_wifi_start() );
    //wifi_connect();
}

/**
 * @description: wifi连接AP
 * @param {char*} fp_ssid
 * @param {char*} fp_pwd
 * @return {*}
 */
static void wifi_connect_ap(char* fp_ssid, char* fp_pwd) {
	wifi_config_t wifi_config = {
		.sta = {
                .threshold.authmode = WIFI_AUTH_WPA2_PSK,
                .sae_pwe_h2e = WPA3_SAE_PWE_BOTH,
                .sae_h2e_identifier = "",
		},
	};		

    memcpy(wifi_config.sta.ssid,     fp_ssid, LEN_OF_WIFI_ENTITY_SSID);
    memcpy(wifi_config.sta.password, fp_pwd,  LEN_OF_WIFI_ENTITY_PWD);	  

    ESP_LOGE(TAG, "WIFI-Connect: %s, PWD: %s.", fp_ssid, fp_pwd);

	ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));					    //设置wifi工作模式为STA
	ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));	    //配置AP参数	
	ESP_ERROR_CHECK(esp_wifi_start());	  								    //打开wifi	
    ESP_ERROR_CHECK(esp_wifi_disconnect());								    
    //st_wifi.status = WIFI_STATUS_ENUM_DISCONNECT;

	ESP_ERROR_CHECK(esp_wifi_connect());								    //连接wifi	
}

/* 开启蓝牙广播 */
static void esp_blufi_adv_start_with_ble_dev_name(char* device_name)
{
    assert(device_name);

    /* Copy Of esp-idf\components\bt\common\btc\profile\esp\blufi\bluedroid_host\esp_blufi.c  */
    static uint8_t blufi_service_uuid128[32] = {
        /* LSB <--------------------------------------------------------------------------------> MSB */
        //first uuid, 16bit, [12],[13] is the value
        0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
    };
    static esp_ble_adv_data_t blufi_adv_data = {
        .set_scan_rsp           = false,
        .include_name           = true,
        .include_txpower        = true,
        .min_interval           = 0x0006, //slave connection min interval, Time = min_interval * 1.25 msec
        .max_interval           = 0x0010, //slave connection max interval, Time = max_interval * 1.25 msec
        .appearance             = 0x00,
        .manufacturer_len       = 0,
        .p_manufacturer_data    =  NULL,
        .service_data_len       = 0,
        .p_service_data         = NULL,
        .service_uuid_len       = 16,
        .p_service_uuid         = blufi_service_uuid128,
        .flag                   = 0x6,
    };

    esp_ble_gap_set_device_name(device_name);
    esp_ble_gap_config_adv_data(&blufi_adv_data);
}

static esp_blufi_callbacks_t blufi_register_callback = {
    .event_cb = blufi_event_callback,
    .negotiate_data_handler = blufi_dh_negotiate_data_handler,
    .encrypt_func = blufi_aes_encrypt,
    .decrypt_func = blufi_aes_decrypt,
    .checksum_func = blufi_crc_checksum,
};

/**
 * @description: 蓝牙配网处理回调函数
 * @param {esp_blufi_cb_event_t} event
 * @param {esp_blufi_cb_param_t} *param
 * @return {*}
 */
static void blufi_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *param)
{
    char tmp_adv_name[30];

    char mac_str[18];    // 存储格式化后的字符串 (17字符 + 空字符)
    get_mac_string(mac_str);

    memset(tmp_adv_name, 0x00, sizeof(tmp_adv_name));
    sprintf(tmp_adv_name, "%s%s", "4DBOX_", mac_str);
    BLUFI_INFO("BLE ADV-NAME: %s", tmp_adv_name);
    /* actually, should post to blufi_task handle the procedure,
     * now, as a example, we do it more simply */
    switch (event) {
    case ESP_BLUFI_EVENT_INIT_FINISH:
        BLUFI_INFO("BLUFI init finish\n");

        // esp_blufi_adv_start();       /* 不修改蓝牙广播内容, 直接启动蓝牙广播 */
        esp_blufi_adv_start_with_ble_dev_name(tmp_adv_name);     /* 特定蓝牙广播内容 */
        break;
    case ESP_BLUFI_EVENT_DEINIT_FINISH:
        BLUFI_INFO("BLUFI deinit finish\n");
        break;
    case ESP_BLUFI_EVENT_BLE_CONNECT:
        BLUFI_INFO("BLUFI ble connect\n");
        ble_is_connected = true;
        esp_blufi_adv_stop();
        blufi_security_init();
        break;
    case ESP_BLUFI_EVENT_BLE_DISCONNECT:
        BLUFI_INFO("BLUFI ble disconnect\n");
        ble_is_connected = false;
        blufi_security_deinit();
        // esp_blufi_adv_start();       /* 不修改蓝牙广播内容, 直接启动蓝牙广播 */
        esp_blufi_adv_start_with_ble_dev_name(tmp_adv_name);     /* 特定蓝牙广播内容 */
        break;
    case ESP_BLUFI_EVENT_SET_WIFI_OPMODE:
        BLUFI_INFO("BLUFI Set WIFI opmode %d\n", param->wifi_mode.op_mode);
        ESP_ERROR_CHECK( esp_wifi_set_mode(param->wifi_mode.op_mode) );
        break;
    case ESP_BLUFI_EVENT_REQ_CONNECT_TO_AP:
        BLUFI_INFO("BLUFI request wifi connect to AP\n");
        /* there is no wifi callback when the device has already connected to this wifi
        so disconnect wifi before connection.
        */

        memset(app_ssid, 0x00, LEN_OF_WIFI_ENTITY_SSID);
        memset(app_pwd,  0x00, LEN_OF_WIFI_ENTITY_PWD);
        memcpy(app_ssid, sta_config.sta.ssid,     sizeof(sta_config.sta.ssid));
        memcpy(app_pwd,  sta_config.sta.password, sizeof(sta_config.sta.password));	

        ESP_LOGE(TAG, "Blufi-WIFI Connecting ..., SSID: %s, PWD: %s.", app_ssid, app_pwd);

        //wifi_connect_ap(app_ssid, app_pwd);

        esp_wifi_disconnect();
        wifi_connect();
        break;
    case ESP_BLUFI_EVENT_REQ_DISCONNECT_FROM_AP:
        BLUFI_INFO("BLUFI request wifi disconnect from AP\n");
        esp_wifi_disconnect();
        break;
    case ESP_BLUFI_EVENT_REPORT_ERROR:
        BLUFI_ERROR("BLUFI report error, error code %d\n", param->report_error.state);
        esp_blufi_send_error_info(param->report_error.state);
        break;
    case ESP_BLUFI_EVENT_GET_WIFI_STATUS: {
        wifi_mode_t mode;
        esp_blufi_extra_info_t info;

        esp_wifi_get_mode(&mode);

        if (gl_sta_connected) {
            memset(&info, 0, sizeof(esp_blufi_extra_info_t));
            memcpy(info.sta_bssid, gl_sta_bssid, 6);
            info.sta_bssid_set = true;
            info.sta_ssid = gl_sta_ssid;
            info.sta_ssid_len = gl_sta_ssid_len;
            esp_blufi_send_wifi_conn_report(mode, gl_sta_got_ip ? ESP_BLUFI_STA_CONN_SUCCESS : ESP_BLUFI_STA_NO_IP, softap_get_current_connection_number(), &info);
        } else if (gl_sta_is_connecting) {
            esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONNECTING, softap_get_current_connection_number(), &gl_sta_conn_info);
        } else {
            esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_FAIL, softap_get_current_connection_number(), &gl_sta_conn_info);
        }
        BLUFI_INFO("BLUFI get wifi status from AP\n");

        break;
    }
    case ESP_BLUFI_EVENT_RECV_SLAVE_DISCONNECT_BLE:
        BLUFI_INFO("blufi close a gatt connection");
        esp_blufi_disconnect();
        break;
    case ESP_BLUFI_EVENT_DEAUTHENTICATE_STA:
        /* TODO */
        break;
	case ESP_BLUFI_EVENT_RECV_STA_BSSID:
        memcpy(sta_config.sta.bssid, param->sta_bssid.bssid, 6);
        sta_config.sta.bssid_set = 1;
        esp_wifi_set_config(WIFI_IF_STA, &sta_config);
        BLUFI_INFO("Recv STA BSSID %s\n", sta_config.sta.ssid);
        break;
	case ESP_BLUFI_EVENT_RECV_STA_SSID:
        if (param->sta_ssid.ssid_len >= sizeof(sta_config.sta.ssid)/sizeof(sta_config.sta.ssid[0])) {
            esp_blufi_send_error_info(ESP_BLUFI_DATA_FORMAT_ERROR);
            BLUFI_INFO("Invalid STA SSID\n");
            break;
        }
        strncpy((char *)sta_config.sta.ssid, (char *)param->sta_ssid.ssid, param->sta_ssid.ssid_len);
        sta_config.sta.ssid[param->sta_ssid.ssid_len] = '\0';
        esp_wifi_set_config(WIFI_IF_STA, &sta_config);
        BLUFI_INFO("Recv STA SSID %s\n", sta_config.sta.ssid);
        break;
	case ESP_BLUFI_EVENT_RECV_STA_PASSWD:
        if (param->sta_passwd.passwd_len >= sizeof(sta_config.sta.password)/sizeof(sta_config.sta.password[0])) {
            esp_blufi_send_error_info(ESP_BLUFI_DATA_FORMAT_ERROR);
            BLUFI_INFO("Invalid STA PASSWORD\n");
            break;
        }
        strncpy((char *)sta_config.sta.password, (char *)param->sta_passwd.passwd, param->sta_passwd.passwd_len);
        sta_config.sta.password[param->sta_passwd.passwd_len] = '\0';
        sta_config.sta.threshold.authmode = WIFI_SCAN_AUTH_MODE_THRESHOLD;
        esp_wifi_set_config(WIFI_IF_STA, &sta_config);
        BLUFI_INFO("Recv STA PASSWORD %s\n", sta_config.sta.password);
        break;
	case ESP_BLUFI_EVENT_RECV_SOFTAP_SSID:
        if (param->softap_ssid.ssid_len >= sizeof(ap_config.ap.ssid)/sizeof(ap_config.ap.ssid[0])) {
            esp_blufi_send_error_info(ESP_BLUFI_DATA_FORMAT_ERROR);
            BLUFI_INFO("Invalid SOFTAP SSID\n");
            break;
        }
        strncpy((char *)ap_config.ap.ssid, (char *)param->softap_ssid.ssid, param->softap_ssid.ssid_len);
        ap_config.ap.ssid[param->softap_ssid.ssid_len] = '\0';
        ap_config.ap.ssid_len = param->softap_ssid.ssid_len;
        esp_wifi_set_config(WIFI_IF_AP, &ap_config);
        BLUFI_INFO("Recv SOFTAP SSID %s, ssid len %d\n", ap_config.ap.ssid, ap_config.ap.ssid_len);
        break;
	case ESP_BLUFI_EVENT_RECV_SOFTAP_PASSWD:
        if (param->softap_passwd.passwd_len >= sizeof(ap_config.ap.password)/sizeof(ap_config.ap.password[0])) {
            esp_blufi_send_error_info(ESP_BLUFI_DATA_FORMAT_ERROR);
            BLUFI_INFO("Invalid SOFTAP PASSWD\n");
            break;
        }
        strncpy((char *)ap_config.ap.password, (char *)param->softap_passwd.passwd, param->softap_passwd.passwd_len);
        ap_config.ap.password[param->softap_passwd.passwd_len] = '\0';
        esp_wifi_set_config(WIFI_IF_AP, &ap_config);
        BLUFI_INFO("Recv SOFTAP PASSWORD %s len = %d\n", ap_config.ap.password, param->softap_passwd.passwd_len);
        break;
	case ESP_BLUFI_EVENT_RECV_SOFTAP_MAX_CONN_NUM:
        if (param->softap_max_conn_num.max_conn_num > 4) {
            return;
        }
        ap_config.ap.max_connection = param->softap_max_conn_num.max_conn_num;
        esp_wifi_set_config(WIFI_IF_AP, &ap_config);
        BLUFI_INFO("Recv SOFTAP MAX CONN NUM %d\n", ap_config.ap.max_connection);
        break;
	case ESP_BLUFI_EVENT_RECV_SOFTAP_AUTH_MODE:
        if (param->softap_auth_mode.auth_mode >= WIFI_AUTH_MAX) {
            return;
        }
        ap_config.ap.authmode = param->softap_auth_mode.auth_mode;
        esp_wifi_set_config(WIFI_IF_AP, &ap_config);
        BLUFI_INFO("Recv SOFTAP AUTH MODE %d\n", ap_config.ap.authmode);
        break;
	case ESP_BLUFI_EVENT_RECV_SOFTAP_CHANNEL:
        if (param->softap_channel.channel > 13) {
            return;
        }
        ap_config.ap.channel = param->softap_channel.channel;
        esp_wifi_set_config(WIFI_IF_AP, &ap_config);
        BLUFI_INFO("Recv SOFTAP CHANNEL %d\n", ap_config.ap.channel);
        break;
    case ESP_BLUFI_EVENT_GET_WIFI_LIST:{
        wifi_scan_config_t scanConf = {
            .ssid = NULL,
            .bssid = NULL,
            .channel = 0,
            .show_hidden = false
        };
        esp_err_t ret = esp_wifi_scan_start(&scanConf, true);
        if (ret != ESP_OK) {
            esp_blufi_send_error_info(ESP_BLUFI_WIFI_SCAN_FAIL);
        }
        break;
    }
    case ESP_BLUFI_EVENT_RECV_CUSTOM_DATA:
        BLUFI_INFO("Recv Custom Data %" PRIu32 "\n", param->custom_data.data_len);
        esp_log_buffer_hex("Custom Data", param->custom_data.data, param->custom_data.data_len);
        esp_blufi_send_custom_data((uint8_t *)"Recv OK!",sizeof("Recv OK!"));
        break;
	case ESP_BLUFI_EVENT_RECV_USERNAME:
        /* Not handle currently */
        break;
	case ESP_BLUFI_EVENT_RECV_CA_CERT:
        /* Not handle currently */
        break;
	case ESP_BLUFI_EVENT_RECV_CLIENT_CERT:
        /* Not handle currently */
        break;
	case ESP_BLUFI_EVENT_RECV_SERVER_CERT:
        /* Not handle currently */
        break;
	case ESP_BLUFI_EVENT_RECV_CLIENT_PRIV_KEY:
        /* Not handle currently */
        break;;
	case ESP_BLUFI_EVENT_RECV_SERVER_PRIV_KEY:
        /* Not handle currently */
        break;
    default:
        break;
    }
}

/*
 * Function:        blufi_net_config_startup
 * Descriptioin:    Blufi 配网启动
 * Input:           没有参数
 * Output:          没有参数
 * Return:          没有返回
 * Calls:           
 * Called By:       
 * Others:
 */
static void blufi_net_config_startup(void)
{
    esp_err_t ret;    

    ret = esp_blufi_host_and_cb_init(&blufi_register_callback);
    if (ret) {
        BLUFI_ERROR("%s initialise failed: %s\n", __func__, esp_err_to_name(ret));
        return;
    }

}

/**
 * @description: 蓝牙配网关闭
 * @return {*}
 */
void blufi_net_config_close(void)
{
    esp_err_t ret;
    esp_blufi_adv_stop();
    blufi_security_deinit();

    xEventGroupClearBits(blufi_event_group, 0xFFFF);
    xEventGroupSetBits(blufi_event_group, BLUFI_NET_CONFIG_BIT_STANDBY); 

    ret = esp_blufi_host_deinit();

    if (ret) {
        BLUFI_ERROR("%s deinit failed: %s\n", __func__, esp_err_to_name(ret));
        return;
    }
}

/*
 * Function:        blufi_config_process_task
 * Descriptioin:   Blufi 配网
 * Input:           没有参数
 * Output:          没有参数
 * Return:          没有返回
 * Calls:           blufi_net_config_startup()
 * Called By:       blufi_net_config_init()
 * Others:
 */
static void blufi_config_process_task(void *para)
{
    esp_err_t ret;

    #if CONFIG_BT_CONTROLLER_ENABLED || !CONFIG_BT_NIMBLE_ENABLED
        ret = esp_blufi_controller_init();
        if (ret) {
            BLUFI_ERROR("%s BLUFI controller init failed: %s\n", __func__, esp_err_to_name(ret));
            return;
        }
    #endif

    BLUFI_INFO("BLUFI VERSION %04x\n", esp_blufi_get_version());

    while (1) {               
        blufi_event_bit = xEventGroupWaitBits(blufi_event_group, BLUFI_ALL_EVENT_BIIS, pdTRUE, pdFALSE, portMAX_DELAY); 

        switch (blufi_event_bit)
        {
        case BLUFI_NET_CONFIG_BIT_STANDBY:
            ESP_LOGW(TAG, "BLUFI_NET_CONFIG_BIT_STANDBY = %d. \n", BLUFI_NET_CONFIG_BIT_STANDBY);
            break;
            
        case BLUFI_NET_CONFIG_BIT_STARTUP:
            ESP_LOGW(TAG, "Blufi Net Config Startup! BLUFI_NET_CONFIG_BIT_STARTUP = %d. \n", BLUFI_NET_CONFIG_BIT_STARTUP);
            blufi_net_config_startup();

            xEventGroupClearBits(blufi_event_group, 0xFFFF);
            xEventGroupSetBits(blufi_event_group, BLUFI_NET_CONFIG_BIT_CONFIGING);  
            break;

        case BLUFI_NET_CONFIG_BIT_CONFIGING:
            ESP_LOGE(TAG, "BLUFI_NET_CONFIG_BIT_CONFIGING = %d. \n", BLUFI_NET_CONFIG_BIT_CONFIGING);
            break;

        case BLUFI_NET_CONFIG_BIT_TIMEOUT:
            ESP_LOGE(TAG, "BLUFI_NET_CONFIG_BIT_TIMEOUT = %d. \n", BLUFI_NET_CONFIG_BIT_TIMEOUT);
            char *str_out = "bluefi timeout";
            esp_blufi_send_custom_data((uint8_t *)str_out, strlen(str_out));

            ESP_LOGE(TAG, "%s", "Blufi Net-Config Timeout!");

            xEventGroupClearBits(blufi_event_group, 0xFFFF);
            xEventGroupSetBits(blufi_event_group, BLUFI_NET_CONFIG_BIT_CLOSE);  
            //blufi_net_config_close();
            break;
        case BLUFI_NET_CONFIG_BIT_CLOSE:
            ESP_LOGE(TAG, "BLUFI_NET_CONFIG_BIT_CLOSE = %d. \n", BLUFI_NET_CONFIG_BIT_CLOSE);
            blufi_net_config_close();
            break;            

        default:
            break;
        }        
    }    
}

/**
 * @description: 蓝牙配网超时判断任务
 * @param {void} *fp_para
 * @return {*}
 */
static void blufi_config_timeout_task(void *fp_para) {
    int counter_second = 0;

    while (1) {       
        vTaskDelay(pdMS_TO_TICKS(1000));  
        if (blufi_event_bit == BLUFI_NET_CONFIG_BIT_CONFIGING) {

            if (counter_second % 10 == 0) 
            {
                ESP_LOGW(TAG, "Blufi is configuring ..., Counter: %d.", counter_second);
            } 

            if ((counter_second ++) >= BLUFI_NET_CONFIG_TIMEOUT) {
                ESP_LOGW(TAG, "Blufi BLUFI_NET_CONFIG_TIMEOUT: %d.", counter_second);

                xEventGroupClearBits(blufi_event_group, 0xFFFF);
                xEventGroupSetBits(blufi_event_group, BLUFI_NET_CONFIG_BIT_TIMEOUT);  
            }  
        } else {
            counter_second = 0;
        }
    }    
}

/**
 * @description: wifi连接任务
 * @param {void} *arg
 * @return {*}
 */
static void wifi_connect_task(void *arg)
{
    wifi_config_t wifi_config;
    while(1)
    {
        /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
        * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
        wifi_event_bit = xEventGroupWaitBits(wifi_event_group, WIFI_ALL_EVENT_BIIS, pdTRUE, pdFALSE, portMAX_DELAY);

        esp_wifi_get_config(WIFI_IF_STA, &wifi_config);

        /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
        * happened. */
        if (wifi_event_bit & WIFI_CONNECTED_BIT) {
            ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
                    wifi_config.sta.ssid, wifi_config.sta.password);

        } else if (wifi_event_bit & WIFI_FAIL_BIT) {
            ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
                    wifi_config.sta.ssid, wifi_config.sta.password); 
        } 
    }
}

/**
 * @description: blufi初始化
 * @return {*}
 */
void blufi_net_config_init(void)
{
    esp_err_t ret;

    // Initialize NVS
    ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK( ret );

    initialise_wifi();

    /* Blufi Event */
    blufi_event_group = xEventGroupCreate();
    if (blufi_event_group == NULL)
    {
        ESP_LOGE(TAG, "%s", "Blufi Event Group Create Failure!");
    }
    blufi_event_bit = BLUFI_NET_CONFIG_BIT_STANDBY;
    xEventGroupClearBits(blufi_event_group, 0xFFFF);
    xEventGroupSetBits(blufi_event_group, BLUFI_NET_CONFIG_BIT_STANDBY);
    
    xTaskCreate(blufi_config_process_task, "Blufi-config-process", 4 * 1024, NULL, 20, NULL);    
    xTaskCreate(blufi_config_timeout_task, "Blufi-Timeout",        3 * 1024, NULL, 14, NULL);
    xTaskCreate(wifi_connect_task, "wifi_connect", 3*1024, NULL, 5, NULL);

    blufi_key_init();
}
